// 定义蛇这个类
class Snake {
    // 表示蛇头的元素
    head: HTMLElement;

    // 表示蛇的身体,包括蛇头
    bodies: HTMLCollection;

    // 表示蛇的容器
    element: HTMLElement;

    constructor() {
        this.element = document.getElementById("snake")!
        this.head = document.querySelector("#snake>div")!;
        this.bodies = this.element.getElementsByTagName("div");
    }

    // 获取蛇头的X坐标
    get X() {
        return this.head.offsetLeft
    }

    // 获取蛇头的Y坐标
    get Y() {
        return this.head.offsetTop
    }

    // 设置蛇的X坐标
    set X(value: number) {
        // 如果值和旧值相同则不修改
        if (this.X === value) return;

        // 修改 X 时，是在修改水片坐标，蛇在向左移动时，不能右掉头。反之亦然
        if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
            console.log(value)
            // 如果发生掉头让蛇反反向移动
            if (value > this.X) {
                // 如果 value 大于 旧值 this.X ，则说明 用户点击的右键，此时发生了掉头，我们应该阻止让其继续向左
                value = this.X - 10;
            } else {
                value = this.X + 10;
            }
        }

        // X 值的合法范围 0-290
        if (value < 0 || value > 290) {
            // 进入说明蛇撞墙了
            throw new Error("蛇撞墙了!")
        }

        // 移动身体
        this.moveBody();
        this.head.style.left = value + "px";
        // 检测有没有撞到自己
        this.checkHeadBody();
    }

    // 设置蛇的Y坐标
    set Y(value: number) {
        // 如果值和旧值相同则不修改
        if (this.Y === value) return;


        if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
            if (value > this.Y) {
                value = this.Y - 10;
            } else {
                value = this.Y + 10;
            }
        }

        // Y 值的合法范围 0-290
        if (value < 0 || value > 290) {
            // 进入说明蛇撞墙了
            throw new Error("蛇撞墙了!")
        }

        // 移动身体
        this.moveBody();
        this.head.style.top = value + "px";
        // 检测有没有撞到自己
        this.checkHeadBody();
    }

    // 添加蛇的身体
    addBody() {
        this.element.insertAdjacentHTML("beforeend", "<div></div>")
    }

    // 蛇身体的移动
    moveBody() {
        /*
        *   将后边的身体设置为前边的身体
        *       例子
        *           第四节 = 第三节的位置
        *           第三节 = 第二节的位置
        *           第二节 = 第一节的位置（蛇头的位置）
         */
        // 遍历所有的身体
        for (let i = this.bodies.length - 1; i > 0; i--) {
            // 获取前边身体位置
            let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
            let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;

            // 将值设置到当前的身体上
            (this.bodies[i] as HTMLElement).style.left = X + 'px';
            (this.bodies[i] as HTMLElement).style.top = Y + 'px';
        }
    }

    // 检测有没有撞到自己
    checkHeadBody() {
        // 获取所有身体，检测是否和蛇头的坐标发生重叠，如果重叠说明发送撞击
        for (let i = 1; i < this.bodies.length; i++) {
            let bd = this.bodies[i] as HTMLElement;
            if (this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
                // 进入判断说明蛇头装到身体，游戏结束
                throw new Error("撞到自己了！")
            }
        }
    }
}

export default Snake;